using System;
using System.Collections.Generic;
using System.Reflection;
using NFreeMarker.Template;

namespace NFreeMarker.Ext.Beans
{
    /**
     * A class that will wrap a reflected method call into a
     * {@link freemarker.template.TemplateMethodModel} interface. 
     * It is used by {@link BeanModel} to wrap reflected method calls
     * for non-overloaded methods.
     * @author Attila Szegedi, szegedia at users dot sourceforge dot net
     * @version $Id: SimpleMethodModel.java,v 1.27 2005/06/11 12:12:04 szegedia Exp $
     */
    public sealed class SimpleMethodModel : SimpleMemberModel, ITemplateMethodModelEx, ITemplateSequenceModel
    {
        private readonly object _object;
        private readonly BeansWrapper _wrapper;

        /**
         * Creates a model for a specific method on a specific object.
         * @param object the object to call the method on. Can be
         * <tt>null</tt> for static methods.
         * @param method the method that will be invoked.
         */
        internal SimpleMethodModel(object obj, MethodInfo method, Type[] argTypes, 
                BeansWrapper wrapper)
            : base(method, argTypes)
        {
            _object = obj;
            _wrapper = wrapper;
        }

        /**
         * Invokes the method, passing it the arguments from the list.
         */
        public object Exec(IList<ITemplateModel> arguments)
        {
            try
            {
                return _wrapper.InvokeMethod(_object, (MethodInfo) GetMember(), 
                    UnwrapArguments(arguments, _wrapper));
            }
            catch (Exception e)
            {
                //while (e is TargetInvocationException)
                //{
                //    Throwable t = ((InvocationTargetException) e).getTargetException();
                //    if (t is Exception)
                //    {
                //        e = (Exception)t;
                //    }
                //    else
                //    {
                //        break;
                //    }
                //}
                //if ((GetMember().getModifiers() & Modifier.STATIC) != 0)
                //{
                //    throw new TemplateModelException("Method " + GetMember() + 
                //            " threw an exception", e);
                //}
                //else
                //{
                //    throw new TemplateModelException("Method " + GetMember() + 
                //            " threw an exception when invoked on " + _object, e);
                //}

                throw new NotImplementedException();
            }
        }

        public object Exec(IList<string> arguments)
        {
            throw new NotSupportedException();
        }

        public ITemplateModel Get(int index)
        {
            //return (ITemplateModel) Exec(Collections12.singletonList(
            //        new SimpleNumber(index)));
            throw new NotImplementedException();
        }

        public int Size()
        {
            throw new TemplateModelException("?size is unsupported for: " + GetType().FullName);
        }
        
        public override string ToString() {
            return GetMember().ToString();
        }
    }
}